package generator.filedeal;

import generator.driver.GeneratorStatistics;
import generator.statistics.NumericalSet;
import generator.structure.Pair;

import java.io.BufferedReader;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileWriter;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.PrintWriter;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
import java.util.Map;
import java.util.Set;

public class ReadFileDeal {

	private int fileNum;
	
	private File[] folder;
	private File fileSample;
	
	private String jointMark;
	
	private NumericalSet numericalSet;
	
	private Map<Pair<String, String>, Integer> jointDistr = new HashMap<Pair<String, String>, Integer>();
	private Map<String, Integer> jointDistrAcum = new HashMap<String, Integer>();
	
	private HashMap<String, Integer> firstMargiDistr = new HashMap<String, Integer>();
	private HashMap<String, Integer> secondMargiDistr = new HashMap<String, Integer>();
	
	//actually the key is stored in a array
	
	private Map<Integer,HashMap<String,Integer>> uncandiDistri = new HashMap<Integer,HashMap<String,Integer>>();
	
	int primaryKey;
	int[] timeCols;
	int[] numericalS;
	int[] hasCompute;
	
	private int cols;
	private int sampleRows;
	private int rows;
	
	public ReadFileDeal(File folder_, File fileSample, String jointMark, int primaryKey, int[] timeCols, int[] numericalS, int[] hasCompute) {
		
		this.fileSample = fileSample;
		this.jointMark = jointMark;
		this.folder = folder_.listFiles();
		
		this.primaryKey = primaryKey;
		this.timeCols = timeCols;
		this.numericalS = numericalS;
		this.hasCompute = hasCompute;
		
	}

	public void setNumericalClass(NumericalSet numericalSet) {
		this.numericalSet = numericalSet;
		initialNumerical();
		
	}
	
	private void initialNumerical() { 
		
		HashMap<Integer, Pair<Integer, Integer>> numerical = new HashMap<Integer, Pair<Integer, Integer>>();
		Pair<Integer, Integer> cate = new Pair<Integer, Integer>(1, null);
		numerical.put(7, cate);
		cate = new Pair<Integer, Integer>(2, 100);
		numerical.put(9, cate);
		numericalSet.setInitial(numerical);
	}
	
	private void setNumericalOffset() {
		for(int i = 0; i < numericalS.length; i++) {
			numericalSet.setOffset(numericalS[i]);
		}
	}
	
	/**
	 * compute the distinct values
	 * @param file
	 */
	public Map<Integer, Set<String>> readData() {
		
		Map<Integer, Set<String>> colDistiVal = new HashMap<Integer, Set<String>>();
		
		try {
			BufferedReader br = new BufferedReader(new InputStreamReader(
					new FileInputStream(fileSample), "UTF-8"));
			
			int totalRows = 0;
			String str;
			System.out.println("Here!!!");

			while ((str = br.readLine()) != null) {
				String[] attrib = str.split(jointMark, -1);
				int i;
				for (i = 0; i < attrib.length; i++) {

					int flag = 0;
					int flagNumerical = 0; 

					if (i == primaryKey)
						continue;
					
					for (int j = 0; j < timeCols.length; j++) {
						if (i == timeCols[j]) {
							flag = 1;
						}
					}

					if (flag == 1)
						continue;

					flag = 0;
					
					for(int j = 0; j < hasCompute.length; j++){
						if (i == hasCompute[j]) {
							flag = 1;
						}
					}
					
					if (flag == 1)
						continue;
					
					String temp = attrib[i]; 

					for (int j = 0; j < numericalS.length; j++) {

						if (i == numericalS[j])
							flagNumerical = numericalS[j];
					}

					if (flagNumerical != 0) {
						numericalSet.recordMax(i, Double.parseDouble(temp));
						continue;
					}

					if (colDistiVal.get(i) == null) {

						Set<String> first = new HashSet<String>();
						first.add(temp);
						colDistiVal.put(i, first);

					} else if (colDistiVal.get(i).contains(temp)) {
						;
					} else {
		
						Set<String> val = colDistiVal.get(i);
						val.add(temp);
						colDistiVal.put(i, val);

					}

					// currCol++; 

				} // for

				this.cols = attrib.length;
				totalRows++;

			}

			System.out.println("totalRows: " + totalRows + " "
					+ colDistiVal.keySet());
			
			this.sampleRows = totalRows;
			br.close();

		} catch (IOException e) {
			e.printStackTrace();
		}

		setNumericalOffset();
		
		return colDistiVal;
	}
	
	/**
	 * statistics the distribution and jointDistribution of two columns
	 * @param column number f
	 * @param column number s
	 * @return
	 */
	@SuppressWarnings("resource")
	public Map<Pair<String, String>, Integer> readData(Integer f, Integer s) {
		
		try {
			BufferedReader br = new BufferedReader(new InputStreamReader(
					new FileInputStream(fileSample), "UTF-8"));
			String str;
			
			firstMargiDistr.clear();
			secondMargiDistr.clear();
			jointDistr.clear();

			int flagf = 0;
			int flags = 0;
		    
			for(int i = 0; i < numericalS.length; i++){
		    	if(f == numericalS[i]) flagf = 1;
		    	if(s == numericalS[i]) flags = 1;
		    }
			
			while ((str = br.readLine()) != null) {
				String[] attrib = str.split(jointMark, -1);
				
				String first = "";
				String second = "";

				if(flagf == 0) first = attrib[f];
				else first = numericalSet.getKey(f, attrib[f]);
				
				if(flags == 0) second = attrib[s];
				else second = numericalSet.getKey(s, attrib[s]);

				if (firstMargiDistr.get(first) == null) {
					firstMargiDistr.put(first, 1);
				} else {
					firstMargiDistr.put(first, firstMargiDistr.get(first) + 1);
				}

				if (secondMargiDistr.get(second) == null) {
					secondMargiDistr.put(second, 1);
				} else {
					secondMargiDistr.put(second,
							secondMargiDistr.get(second) + 1);
				}

				Pair<String, String> elem = new Pair<String, String>(first,
						second);

				if (jointDistr.get(elem) == null) {
					jointDistr.put(elem, 1);
				} else {
					jointDistr.put(elem, jointDistr.get(elem) + 1);
				}

			}
		} catch (IOException e) {
			e.printStackTrace();
		}

		return jointDistr;
	}
	
	/**
	 * scan of full table
	 * @param c
	 */
	public void readData(String c) {
		
		BufferedReader br;
		for(File fileName : folder){
				
			try{
				
				br = new BufferedReader(new InputStreamReader(new FileInputStream(fileName), "UTF-8"));
				String str;	
		
				while((str = br.readLine()) != null){
					
					rows++;
					String[] attrib = str.split(jointMark,-1);
					
					for(int i = 0; i < numericalS.length; i++){
				    	int column = numericalS[i];
				    	numericalSet.recordMax(column, Double.parseDouble(attrib[column]));
				    }
					
				}
				
			} catch (IOException e) {
				e.printStackTrace();
			}
			
		}//for every file in folder
		
		setNumericalOffset();
	}
	
	/**
	 * the input of lda
	 */
	ArrayList<Integer> rowsArray = new ArrayList<Integer>();
	
	@SuppressWarnings("resource")
	public ArrayList<Map<String,Integer>> readData(ArrayList<Integer> circleArray){
		
		ArrayList<Map<String, Integer>> currentDistributionList = new ArrayList<Map<String, Integer>>();
		
//		jointDistrCircle.clear();
		rowsArray.clear();
		BufferedReader br;
//		int rows = 0;
		
		//judge whether it is numericalSet
		int length = circleArray.size();
		int[] flag = new int[length];
		
		for(int i = 0; i < numericalS.length; i++){
			for(int j = 0; j < length; j++) {
				if(circleArray.get(j) == numericalS[i]) flag[j] = 1;
			}
	    }
		
		//!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
		Map<String,Integer> priDistrCircle = new HashMap<String, Integer>();
		
		for(File fileName : folder){
			int rows = 0;
			Map<String,Integer> jointDistrCircle = new HashMap<String, Integer>();
			
			try{
				
				br = new BufferedReader(new InputStreamReader(new FileInputStream(fileName), "UTF-8"));
				String str;	
		
				while((str = br.readLine()) != null){
					
					rows++;
					String[] attrib = str.split(jointMark,-1);
					
					String elem = "";
					for(int i = 0; i < length; i++){
						int column = circleArray.get(i);
						//deal with numerical and category
						if(flag[i] == 0) elem += attrib[column] + ",";
						else elem += GeneratorStatistics.numericalSet.getKey(column, attrib[column]) + ",";
					}
					
					elem = elem.substring(0, elem.length() - 1);
					
					if(jointDistrCircle.get(elem) == null){
						jointDistrCircle.put(elem, 1);
					} else {
						jointDistrCircle.put(elem, jointDistrCircle.get(elem)+1);
					}
					
					//!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
					if(priDistrCircle.get(elem) == null){
						priDistrCircle.put(elem, 1);
					} else {
						priDistrCircle.put(elem, priDistrCircle.get(elem)+1);
					}
					
				}
				
			} catch (IOException e) {
				e.printStackTrace();
			}
			
			rowsArray.add(rows);
			
			currentDistributionList.add(jointDistrCircle);
			
		}//for every file in folder
		
//		this.rows = rows;
		
//		System.out.println(priDistrCircle.size());
//		
//		try {
//			PrintWriter pw = new PrintWriter(new FileWriter("e:/distribution1.txt"));
//			pw.println(priDistrCircle);
//			pw.close();
//		} catch (IOException e) {
//			// TODO Auto-generated catch block
//			e.printStackTrace();
//		}
		
		return currentDistributionList;
	
	}
	
	public Map<Integer,HashMap<String,Integer>> getUncandiDistri(Set<Integer> s){
		
		uncandiDistri.clear();
		
		for(File fileName : folder){
			
			try {
				BufferedReader br = new BufferedReader(new InputStreamReader(new FileInputStream(fileName), "UTF-8"));				
				
				String str;	
				
				while ((str = br.readLine()) != null) {
					String[] attrib = str.split(jointMark,-1);
					
					for (Iterator<Integer> it = s.iterator(); it.hasNext(); ) { 
						Integer colNum = it.next();								
						String val = attrib[colNum];						
						
						HashMap<String,Integer> ht = new HashMap<String,Integer>();
						
						if (uncandiDistri.get(colNum) == null) {				
							ht.put(val,1);
							uncandiDistri.put(colNum, ht);
							
						} else if (uncandiDistri.get(colNum).get(val) == null) {
									HashMap<String,Integer> ht2 = uncandiDistri.get(colNum);
									ht2.put(val, 1);
									uncandiDistri.put(colNum, ht2);
								} else {
									HashMap<String,Integer> ht1 = uncandiDistri.get(colNum);
									ht1.put(val, uncandiDistri.get(colNum).get(val)+1);
									uncandiDistri.put(colNum, ht1);
								}
					}//for
						
				}//while
					
				br.close();
			} catch (IOException e) {
				e.printStackTrace();
			}
			
		}//for every file in folder
		

		return uncandiDistri;
	}
	
	
	
	//-----------------------get function--------------------------
	
	public int getRows(String c) {
		if(c == "s")
			return sampleRows;
		else
			return rows;
	}
	
	public int getCols() {
		return cols;
	}
	
	public int getFileNum() {
		return fileNum = folder.length;
	}
	
	public  ArrayList<Integer> getRowsArray() {
		return rowsArray;
	}
	
	/**
	 * use in class GetTwoSets
	 * @return
	 */
	public  HashMap<String, Integer> getFirstMargiDistr() {
		return firstMargiDistr;
	}
	
	public  HashMap<String, Integer> getSecondMargiDistr() {
		return secondMargiDistr;
	}
	
	public Map<Pair<String, String>, Integer> getJointDistr() {
		return jointDistr;
	}
	
	
}
